import * as THREE from 'three';
import { createCameraTween } from '../tools/useTween';
import { Y_LAYERS } from '../tools/constants';

/**
 * @description 旋转策略
 */
const rotateYStrategies: Record<Editor.AroundSideMeshKeys, number> = {
  left: Math.PI / 2,
  right: -Math.PI / 2,
  front: -Math.PI,
  back: 0,
};

/**
 * @description sideDevice键盘移动策略
 */
interface ArrowKeyBoardMoveStrategy {
  leftRightArrowAxis: 'x' | 'y' | 'z';
  leftArrowDirection: number;
  rightArrowDirection: number;
  upDownArrowAxis: 'x' | 'y' | 'z';
  upArrowDirection: number;
  downArrowDirection: number;
}

const arrowKeyBoardMoveStrategies: Record<Editor.AroundSideMeshKeys, ArrowKeyBoardMoveStrategy> = {
  left: {
    leftRightArrowAxis: 'z',
    leftArrowDirection: 1,
    rightArrowDirection: -1,
    upDownArrowAxis: 'y',
    upArrowDirection: 1,
    downArrowDirection: -1,
  },
  right: {
    leftRightArrowAxis: 'z',
    leftArrowDirection: -1,
    rightArrowDirection: 1,
    upDownArrowAxis: 'y',
    upArrowDirection: 1,
    downArrowDirection: -1,
  },
  front: {
    leftRightArrowAxis: 'x',
    leftArrowDirection: 1,
    rightArrowDirection: -1,
    upDownArrowAxis: 'y',
    upArrowDirection: 1,
    downArrowDirection: -1,
  },
  back: {
    leftRightArrowAxis: 'x',
    leftArrowDirection: -1,
    rightArrowDirection: 1,
    upDownArrowAxis: 'y',
    upArrowDirection: 1,
    downArrowDirection: -1,
  },
};

/**
 * 定位参数接口
 */
interface LocateParams<T extends Editor.Building | Editor.Field> {
  building: T;
  sideType: Editor.AroundSideMeshKeys;
  device: Editor.Device;
  camera: THREE.PerspectiveCamera;
  controls: Editor.Controls;
  isNewDevice: boolean;
}

/**
 * @description 不同类型设备的定位策略
 * 最终要实现的效果：
 *  设备的坐标保存的就是当前坐标
 *  当building的基准点移动时，group的基准点相应的移动
 *
 * 我需要验证的情况：
 *  1.有一批预渲染设备
 *  2.移动大棚
 *  3.相应的移动group
 */
const locateStrategies: Record<Editor.DeviceType, (params: LocateParams<Editor.Building>) => void> = {
  sideDevice: (params: LocateParams<Editor.GreenHouse>) => {
    const { device, camera, controls, building, isNewDevice, sideType = 'right' } = params;
    const { center: buildingCenter, basePoint: buildingBasePoint } = building.getInfo();
    const { orbitControls, transformControls } = controls;
    const { model } = device;
    // 新增时才调整模型位置
    if (isNewDevice) {
      if (typeof building.getSideMeshInfo === 'function') {
        const { center: sideCenter } = building.getSideMeshInfo(sideType);

        // 设备模型初始化位置

        // 使用useTween调整 camera.position + orbitControls.target(这里使用世界坐标)
        createCameraTween({ camera, controls: orbitControls, endPos: buildingCenter, endTarget: sideCenter, duration: 1000 });
        // 计算模型的新位置
        // 1.旋转修正
        model.rotateY(rotateYStrategies[sideType]);
        const fixedSideCenter = sideCenter.clone().sub(buildingBasePoint);
        // MARK: 这里使用相对坐标
        model.position.copy(fixedSideCenter);
      }
    } else {
      /** 这里应该的endPos合target应该根据已有的模型计算 */
      const { center: deviceCenter } = device.getInfo();
      createCameraTween({ camera, controls: orbitControls, endPos: buildingCenter, endTarget: deviceCenter, duration: 1000 });
    }
    transformControls.attach(model);
  },
  insideDevice: (params: LocateParams<Editor.Building>) => {
    const { building, camera, controls, device, isNewDevice } = params;
    const { center: buildingCenter, size: buildingSize } = building.getInfo();
    const { orbitControls, transformControls } = controls;

    // 调整模型位置
    const { model } = device;
    /**
     * 设置target后，滚动失效了
     * 测试发现必须要有一个维度是0，zoom才生效
     */
    let computedY = 0;
    /** 向下偏移1/10 如果Y值太小，用X值定位 */
    if (Math.abs(buildingSize.x / buildingSize.y) > 10) {
      computedY = buildingSize.x - buildingSize.x / 10;
    } else {
      computedY = buildingSize.y - buildingSize.y / 10;
    }

    if (isNewDevice) {
      model.rotateX(Math.PI / 2);

      const endPos = new THREE.Vector3(buildingCenter.x, computedY, buildingCenter.z);
      /** 俯视时: y设置为0 */
      const endTarget = new THREE.Vector3(buildingCenter.x, 0, buildingCenter.z);
      createCameraTween({ camera, controls: orbitControls, endPos, endTarget, duration: 1000 });
      // 计算模型的新位置 FIXME: 这里的y应该替换为内部设备的基础层级?
      model.position.set(endTarget.x, endTarget.y + Y_LAYERS.INSIDE_DEVICE, endTarget.z);
    } else {
      const { center: deviceCenter } = device.getInfo();
      const endPos = new THREE.Vector3(deviceCenter.x, computedY, deviceCenter.z);
      createCameraTween({ camera, controls: orbitControls, endPos, endTarget: deviceCenter, duration: 1000 });
    }
    transformControls.attach(model);
  },
};

/**
 * 控制器参数接口
 */
interface ControlsParams {
  controls: Editor.Controls;
  /** 是否开启快速旋转，默认开启 */
  enableFastRotate?: boolean;
}

/**
 * @description 不同类型设备的控制器策略
 */
const controlsStrategies: Record<Editor.DeviceType, (params: ControlsParams) => void> = {
  sideDevice: (params) => {
    const { controls, enableFastRotate = true } = params;
    const { transformControls } = controls;
    // 开启编辑菜单
    controls.enableTransformModeMenu({
      enableFastRotate,
      initialMode: 'translate',
      visibleModes: [
        {
          mode: 'translate',
          callback: () => {
            transformControls.showX = true;
            transformControls.showY = false;
            transformControls.showZ = true;
          },
        },
        {
          mode: 'rotate',
          callback: () => {
            transformControls.showX = false;
            transformControls.showY = true;
            transformControls.showZ = false;
          },
        },
      ],
    });
  },
  insideDevice: (params) => {
    const { controls, enableFastRotate = true } = params;
    const { transformControls } = controls;
    // 开启编辑菜单
    controls.enableTransformModeMenu({
      enableFastRotate,
      initialMode: 'translate',
      visibleModes: [
        {
          mode: 'translate',
          callback: () => {
            transformControls.showX = true;
            transformControls.showY = false;
            transformControls.showZ = true;
          },
        },
        {
          mode: 'rotate',
          callback: () => {
            transformControls.showX = false;
            transformControls.showY = true;
            transformControls.showZ = false;
          },
        },
      ],
    });
  },
};

/**
 * 键盘参数接口
 */
interface KeyboardParams {
  keyboardAbortController: AbortController;
  controls: Editor.Controls;
  camera: THREE.PerspectiveCamera;
  sideType: keyof Editor.SideMeshType; // 贴边类型（用于定位）
  building: Editor.Building | Editor.Field;
}

/**
 * @description 不同类型设备的键盘控制策略
 */
const keyboardStrategies: Record<Editor.DeviceType, (params: KeyboardParams) => void> = {
  sideDevice: (params) => {
    const { keyboardAbortController, controls, building, camera, sideType = 'right' } = params;
    const { transformControls, orbitControls } = controls;
    const { size } = building.getInfo();
    // 获取当前方向的控制策略
    const strategy = arrowKeyBoardMoveStrategies[sideType] || arrowKeyBoardMoveStrategies.left;

    // 映射键盘事件到策略
    const keyMap: Record<string, { axis: 'x' | 'y' | 'z'; direction: number }> = {
      ArrowLeft: { axis: strategy.leftRightArrowAxis, direction: strategy.leftArrowDirection },
      ArrowRight: { axis: strategy.leftRightArrowAxis, direction: strategy.rightArrowDirection },
      ArrowUp: { axis: strategy.upDownArrowAxis, direction: strategy.upArrowDirection },
      ArrowDown: { axis: strategy.upDownArrowAxis, direction: strategy.downArrowDirection },
    };
    // 步长
    const stepSizes: Record<'x' | 'y' | 'z', number> = {
      x: size.x / 50,
      y: size.z / 50,
      z: size.x / 50,
    };

    document.addEventListener(
      'keydown',
      (event: KeyboardEvent) => {
        const keyConfig = keyMap[event.key];
        if (!keyConfig) return;
        const { axis, direction } = keyConfig;
        // 步长
        const step = stepSizes[axis] * direction;
        event.preventDefault();

        // 更新相机和控制器位置
        camera.position[axis] += step;
        orbitControls.target[axis] += step;

        if (transformControls.object) {
          transformControls.object.position[axis] += step;
        }
      },
      {
        signal: keyboardAbortController.signal,
      }
    );
  },
  insideDevice: (params) => {
    const { keyboardAbortController, controls, building, camera } = params;
    const { transformControls, orbitControls } = controls;
    const { size } = building.getInfo();
    document.addEventListener(
      'keydown',
      (event: KeyboardEvent) => {
        event.preventDefault();
        const leftRightAxis = 'x';
        const leftRightStep = size.x / 20;
        const upDownAxis = 'z';
        const upDownStep = size.z / 20;
        if (event.key === 'ArrowLeft') {
          // 向Z轴正方形移动1，且orbitControl跟随变化
          camera.position[leftRightAxis] -= leftRightStep;
          orbitControls.target[leftRightAxis] -= leftRightStep;
          if (transformControls.object) {
            transformControls.object.position[leftRightAxis] -= leftRightStep;
          }
        } else if (event.key === 'ArrowRight') {
          camera.position[leftRightAxis] += leftRightStep;
          orbitControls.target[leftRightAxis] += leftRightStep;
          if (transformControls.object) {
            transformControls.object.position[leftRightAxis] += leftRightStep;
          }
        } else if (event.key === 'ArrowUp') {
          transformControls.object.position[upDownAxis] -= upDownStep;
          // 视角跟随
          camera.position[upDownAxis] -= upDownStep;
          orbitControls.target[upDownAxis] -= upDownStep;
        } else if (event.key === 'ArrowDown') {
          transformControls.object.position[upDownAxis] += upDownStep;
          // 视角跟随
          camera.position[upDownAxis] += upDownStep;
          orbitControls.target[upDownAxis] += upDownStep;
        }
      },
      {
        signal: keyboardAbortController.signal,
      }
    );
  },
};

const Strategies = {
  /** 定位 */
  locateStrategies,
  /** 控制器 */
  controlsStrategies,
  /** 键盘 */
  keyboardStrategies,
};

export default Strategies;
